package com.lilanz.facepass.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lilanz.facepass.controller.push.dto.Message;
import com.lilanz.facepass.dao.ClientMapper;
import com.lilanz.facepass.entity.client.Client;
import com.lilanz.facepass.entity.exception.MyException;
import com.lilanz.facepass.service.IHTTPService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

@Service
@PropertySource({"classpath:application.properties"})//引入外部资源文件
public class HTTPServiceImpl implements IHTTPService {
    @Resource
    private ClientServiceImpl clientService;


    @Value("${facepass.token}")
    private String getTokenUrl;
    @Value("${facepass.refreshToken}")
    private String getRefreshTokenUrl;

    @Override
    public JSONObject sendPost(String url, String token, Map<String, String> paramMap) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            if (StringUtils.isEmpty(url)) {
                throw new MyException("请输入url");
            }
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            HttpURLConnection conn = ((HttpURLConnection) realUrl.openConnection());
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("Authorization", token);
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Charset", "UTF-8");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());

            // 设置请求属性
            StringBuilder param = getStringBuilder(paramMap);

            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();

            if (conn.getResponseCode() == 401) {//访问令牌过期
                Client client = clientService.selectOne();
                Map<String, String> map = new HashMap<>();
                map.put("clientId", client.getClientId());
                map.put("refreshToken", client.getRefreshToken());
                map.put("grantType", client.getGrantType());
                updateToken(map);
                throw new MyException("请重试");
            }

            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }

            JSONObject jb = JSONObject.parseObject(result.toString());
            String success = jb.getString("success");
            if (success.equals("1")) {
                //正确
                return JSONObject.parseObject(jb.getString("data"));
            } else {
                //错误
                throw new MyException(jb.getString("message") + " 错误来源瑞云服务器的错误");
            }


        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(e.getMessage());
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            closeStream(out, in);
        }
    }

    @Override
    public JSONObject sendJson(String url, Object obj) {
        try {
            String content = JSON.toJSONString(obj);
            System.out.println("传送的数据json " + content);
            // 创建url资源
            URL realUrl = new URL(url);
            // 建立http连接
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            //转换为字节数组
            byte[] data = content.getBytes();
            // 设置文件长度
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));

            // 设置文件类型:
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            // 设置接收类型否则返回415错误
            //conn.setRequestProperty("accept","*/*")此处为暴力方法设置接受所有类型，以此来防范返回415;
            conn.setRequestProperty("accept", "application/json");

            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write(content.getBytes());
            out.flush();
            out.close();

            System.out.println(conn.getResponseCode());

            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                System.out.println("连接成功");
                // 请求返回的数据
                try (InputStream in = conn.getInputStream()) {
                    byte[] data1 = new byte[in.available()];
                    in.read(data1);
                    // 转成字符串
                    return JSONObject.parseObject(new String(data1));
                } catch (Exception e1) {
                    e1.printStackTrace();
                    throw new MyException("   原因为: " + e1.getMessage());
                }
            } else {
                System.out.println("no++");
            }
        } catch (Exception e) {
            throw new MyException("   原因为: " + e.getMessage());
        }
        return null;
    }


    @Override
    public void updateToken(Map<String, String> paramMap) {
        PrintWriter out = null;
        BufferedReader in = null;
        try {
            HttpURLConnection conn = getHttpURLConnection(getTokenUrl);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 设置请求属性
            StringBuilder param = getStringBuilder(paramMap);
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            if (conn.getResponseCode() == 401) {//刷新令牌过期了
                updateRefreshToken();
            } else {
                StringBuilder result = new StringBuilder();
                // 定义BufferedReader输入流来读取URL的响应
                in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }

                //获取新数据并且更新最新的token
                JSONObject jb = JSONObject.parseObject(result.toString());
                String success = jb.getString("success");
                if (success.equals("1")) {
                    String data = jb.getString("data");
                    JSONObject jb1 = JSONObject.parseObject(data);
                    String clientId = jb1.getString("clientId");
                    String token = jb1.getString("token");
                    String effectiveDate = jb1.getString("tokenEffectiveDate");
                    Client client = new Client();
                    client.setClientId(clientId);
                    client.setTokenEffectiveDate(new Date(Long.valueOf(effectiveDate)));
                    client.setToken(token);
                    clientService.updateByClientId(client);
                } else {
                    throw new MyException(jb.getString("message"));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(e.getMessage());
        } finally {
            closeStream(out, in);
        }
    }


    @Override
    public void updateRefreshToken() {
        PrintWriter out = null;
        BufferedReader in = null;
        Client client = clientService.selectOne();
        Map<String, String> map = new HashMap<>();
        map.put("clientId", client.getClientId());
        map.put("clientSecret", client.getClientSecret());
        map.put("grantType", client.getGrantType());
        try {
            HttpURLConnection conn = getHttpURLConnection(getRefreshTokenUrl);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 设置请求属性
            StringBuilder param = getStringBuilder(map);
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();

            StringBuilder result = new StringBuilder();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }

            //获取新数据并且更新最新的token
            JSONObject jb = JSONObject.parseObject(result.toString());
            String success = jb.getString("success");
            if (success.equals("1")) {
                String data = jb.getString("data");
                JSONObject jb1 = JSONObject.parseObject(data);
                String clientId = jb1.getString("clientId");
                String token = jb1.getString("token");
                String effectiveDate = jb1.getString("tokenEffectiveDate");
                String refreshToken = jb1.getString("refreshToken");
                Client client1 = new Client();
                client1.setClientId(clientId);
                client1.setTokenEffectiveDate(new Date(Long.valueOf(effectiveDate)));
                client1.setToken(token);
                client1.setRefreshToken(refreshToken);
                clientService.updateByClientId(client1);
            } else {
                throw new MyException(jb.getString("message"));
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(e.getMessage());
        } finally {
            closeStream(out, in);
        }
    }


    private void closeStream(PrintWriter out, BufferedReader in) {
        try {
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }


    public static Map<String, String> getNamValMap(Object obj, boolean isSort) {
        Map<String, String> map = null;
        if (isSort) {
            map = new TreeMap<String, String>();
        } else {
            map = new HashMap<String, String>();
        }
        Field[] fieldArr = obj.getClass().getDeclaredFields();
        try {
            for (Field field : fieldArr) {
                field.setAccessible(true);
                if (field.get(obj) != null && !"".equals(field.get(obj).toString())) {
                    map.put(field.getName(), field.get(obj).toString());
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new MyException(e.getMessage());
        }
        return map;
    }


    private HttpURLConnection getHttpURLConnection(String getTokenUrl) throws IOException {
        URL realUrl = new URL(getTokenUrl);
        // 打开和URL之间的连接
        HttpURLConnection conn = ((HttpURLConnection) realUrl.openConnection());
        // 设置通用的请求属性
        conn.setRequestProperty("accept", "*/*");
        conn.setRequestProperty("connection", "Keep-Alive");
        conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        conn.setRequestProperty("Charset", "UTF-8");
        // 发送POST请求必须设置如下两行
        conn.setDoOutput(true);
        conn.setDoInput(true);
        return conn;
    }

    private static StringBuilder getStringBuilder(Map<String, String> paramMap) {
        StringBuilder param = new StringBuilder();
        if (paramMap != null && paramMap.size() > 0) {
            for (String key : paramMap.keySet()) {
                String value = paramMap.get(key);
                param.append(key).append("=").append(value).append("&");
            }
            param = new StringBuilder(param.substring(0, param.length() - 1));
        }
        return param;
    }


}
